import threading
from time import sleep
import queue

class Producer(threading.Thread):
    """
    生产者线程类，负责向队列中放入数据
    继承自threading.Thread，必须实现run()方法
    """
    def __init__(self, threadname):
        # 初始化线程，设置线程名称
        threading.Thread.__init__(self, name=threadname)
    
    def run(self):
        """
        线程主逻辑：循环10次，每次向队列放入一个数字
        """
        for i in range(10):
            # 将数字i放入队列（线程安全操作）
            myqueue.put(i)
            # 打印生产日志
            print(self.name, 'put', i, 'to queue.')
            # 模拟生产耗时
            sleep(0.8)

class Consumer(threading.Thread):
    """
    消费者线程类，负责从队列取出数据
    """
    def __init__(self, threadname):
        # 初始化线程，设置线程名称
        threading.Thread.__init__(self, name=threadname)
    
    def run(self):
        """
        线程主逻辑：循环10次，每次从队列取出一个数据
        """
        for i in range(10):
            # 从队列获取数据（阻塞操作，队列空时会等待）
            data = myqueue.get()
            # 打印消费日志
            print(self.name, 'get', data, 'from queue.')
            # 模拟消费耗时
            sleep(1.5)

# 创建线程安全的队列（先进先出）
myqueue = queue.Queue()

# 启动生产者线程
Producer('Producer').start()

# 主线程等待2秒，确保队列中有数据
sleep(2)

# 启动消费者线程
Consumer('Consumer').start()

# 程序执行流程说明：
# 1. 生产者先运行，开始往队列放数据(每0.8秒一个)
# 2. 2秒后消费者启动，此时队列已有2-3个数据
# 3. 消费者以较慢速度(每1.5秒一个)消费数据
# 4. 由于生产速度 > 消费速度，队列会逐渐积压数据
# 5. 当生产者结束后，消费者会继续消费队列剩余数据